package com.lty.redis;

import cn.hutool.core.util.StrUtil;
import com.lty.exception.BusinessException;
import com.lty.common.ErrorCode;
import com.lty.util.IpInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 限流拦截器
 * @author lty
 */
@Slf4j
@Component
public class LimitRaterInterceptor implements HandlerInterceptor {

    @Resource
    private RedisRaterLimiter redisRaterLimiter;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String ip = IpInfoUtil.getIpAddress(request);

        // 注解限流
        try {
            // 用bean,method,ip 当作限流标识
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Object bean = handlerMethod.getBean();
            Method method = handlerMethod.getMethod();
            RateLimiter rateLimiter = method.getAnnotation(RateLimiter.class);
            if (rateLimiter != null) {
                String name = rateLimiter.name();
                Long limit = rateLimiter.rate();
                Long timeout = rateLimiter.rateInterval();
                if (StrUtil.isBlank(name)) {
                    name = StrUtil.subBefore(bean.toString(), "@", false) + "_" + method.getName();
                }
                if (rateLimiter.ipLimit()) {
                    name += "_" + ip;
                }
                log.info("limit_name:" + name);
                Boolean token3 = redisRaterLimiter.acquireByRedis(name, limit, timeout);
                if (!token3) {
                    String msg = "当前访问人数太多啦，请稍后再试";
                    if (rateLimiter.ipLimit()) {
                        msg = "你手速怎么这么快，请点慢一点";
                    }
                    throw new BusinessException(ErrorCode.OPERATION_ERROR, msg);
                }
            }
        } catch (BusinessException e) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, e.getMessage());
        } catch (Exception e) {

        }
        return true;
    }
}
